﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Common.Dao;
using Common.Model;
using GxTsSharp.Models;
using log4net;
using Quartz.Util;

namespace StockIndex.service
{
    //量比计算 量比=（现成交总手数 / 现累计开市时间(分) ）/ 过去5日平均每分钟成交量
    public class LiangbiService
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(LiangbiService));

        /// <summary>
        /// 计算板块量比,定时任务调用，每分钟一次
        /// </summary>
        public static void CalcLiangbi()
        {            
            ConcurrentDictionary<string, decimal> dic5DaysTopicAvgVolumn = MemoryDataDB.Dic5DaysTopicAvgVolumn;
            ConcurrentDictionary<string, decimal> dicTopicLiangbi = MemoryDataDB.DicTopicLiangbi;
            ConcurrentDictionary<string, decimal> dicTopicVolumn = MemoryDataDB.DicTopicVolumn;
            DateTime nowTime = DateTime.Now;

            if (dic5DaysTopicAvgVolumn.Count == 0)
            {
                Log.Debug("未计算5日平均成交量，放弃计算量比");
                return;
            }

            DateTime closeTime = DateTime.Today.AddHours(15);
            DateTime openTime = DateTime.Today.AddHours(9).AddMinutes(30);
            decimal minutes = 0;
            decimal zaopanMinutes = 120;
            
            if (nowTime >= openTime && nowTime <= closeTime)
            {
                minutes = (nowTime.Minute - openTime.Minute) + ((nowTime.Hour - openTime.Hour) * 60);
                if (minutes > zaopanMinutes)
                {
                    minutes -= 90;
                }
            }
            else if(nowTime>closeTime)
            {
                minutes = 240;
            }

            if (minutes ==0)
            {
                Log.Debug("未到达当天开盘时间，放弃计算量比");
                return;
            }
            
            Log.Info("开始计算量比");
            
            Log.Debug($"量比分钟数：{minutes}");
            
            ConcurrentDictionary<string, StockReport> stockSnapshoot = MemoryDataDB.StockSnapshoot;

            foreach (var topic in dic5DaysTopicAvgVolumn.Keys.ToList())
            {
                HashSet<string> stocks = MemoryDataDB.TopicStocks.TryGetAndReturn(topic);
                decimal totalVol = stocks.Select(m =>
                {
                    StockReport reportTotal = stockSnapshoot.TryGetAndReturn(m);
                    if (null == reportTotal)
                    {
                        Log.Info(
                            $"主题名称：{topic},StockSnapshoot无法找到对应行情数据,股票代码:{m}");
                    }
                    return null == reportTotal ? 0 : (decimal) reportTotal.Report.Total;
                }).Sum();
                dicTopicVolumn.AddOrUpdate(topic, totalVol, (k, v) => totalVol);
                
                decimal avgMinuteVol = dic5DaysTopicAvgVolumn.TryGetAndReturn(topic)/ 240;
                if (avgMinuteVol == 0)
                {
                    Log.Info("主题："+topic+" 5日平均量比为0，数据异常，放弃计算");
                    continue;
                }
                decimal liangbi = 0;
                if (minutes == 0)
                {
                    dicTopicLiangbi.AddOrUpdate(topic, liangbi, (k, v) => liangbi);
                }
                else
                {
                    liangbi = (totalVol / minutes) / avgMinuteVol;
                    dicTopicLiangbi.AddOrUpdate(topic, liangbi, (k, v) => liangbi);
                }
                
                if (topic.Equals("新能源车"))
                {
                    Log.Debug(
                        $"主题名称：{topic},成交量:{dicTopicVolumn},过去5日平均每分钟成交量:{avgMinuteVol},量比:{liangbi},股票数量:{stocks.Count}");
                }
            }
           
           Log.Info("完成计算量比");
        }
        
        
        /// <summary>
        /// 计算5日平均成交量,定时任务调用，每日开盘调用一次
        /// </summary>
        public static void CalcVolumn()
        {
            ConcurrentDictionary<string, decimal> dic5DaysStockAvgVolumn = MemoryDataDB.Dic5DaysStockAvgVolumn;
            ConcurrentDictionary<string, decimal> dic5DaysTopicAvgVolumn = MemoryDataDB.Dic5DaysTopicAvgVolumn;
            DateTime yesterday = DateTime.Today;
            
            List<DateTime> lastNBeginDateAndEndDateWithoutToday = TradeDateDao.GetLastNBeginDateAndEndDateWithoutToday(5, yesterday);
            List<LbMode> listCjl =
                DailyKLineDao.GetCjl(lastNBeginDateAndEndDateWithoutToday.Min(m => m).AddDays(1), yesterday);

            List<string> stockCodeList = listCjl.Select(m=>m.StockCode).Distinct().ToList();
            Log.Info("开始计算个股5日平均成交量");
            foreach (string stockCode in stockCodeList)
            {
                List<LbMode> stocks = listCjl.Where(m => m.StockCode.EndsWith(stockCode) && m.Volume != 0).ToList();
                decimal volunm = stocks.Sum(m => (decimal) m.Volume) / stocks.Count();
                dic5DaysStockAvgVolumn.AddOrUpdate(stockCode, volunm, (k, v) => volunm);
                
                if (stockCode.Equals("000001.SZ"))
                {
                    Log.Debug($"股票代码：{stockCode},5日平均成交量:{volunm},k线数量:{stocks.Count}");
                }
            }
            Log.Info("完成计算个股5日平均成交量");
            List<string> topics = MemoryDataDB.TopicStocks.Keys.ToList();
            
            Log.Info("开始计算主题5日平均成交量");
            foreach (string topic in topics)
            {
                HashSet<string> stocks = MemoryDataDB.TopicStocks.TryGetAndReturn(topic);
                decimal volunm = 0;
                foreach (var stock in stocks)
                {
                    volunm += dic5DaysStockAvgVolumn.TryGetAndReturn(stock);
                }
                dic5DaysTopicAvgVolumn.AddOrUpdate(topic, volunm, (k, v) => volunm);
                
                if (topic.Equals("新能源车"))
                {
                    Log.Debug($"主题名称：{topic},5日平均成交量:{volunm},股票数量:{stocks.Count}");
                }
            }
            Log.Info("完成计算主题5日平均成交量");
        }
    }
}